home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_200 / 233_01 / make.c < prev    next >
Text File  |  1987-06-29  |  13KB  |  527 lines

  1. /* 
  2.  *     Program Name    : MAKE.C
  3.  *    Author        : Allen Holub
  4.  *    Implementor    : Kenji Hino
  5.  *    Compiler    : Microsoft ver. 4.0, Lattice C ver. 3
  6.  *    Description    : MAKE is the program that maintains programs.
  7.  *              MAKE takes resposibility for recompiling or linking
  8.  *              any source or object codes if any of them has 
  9.  *              updated.
  10.  */ 
  11.  
  12. #include "make.h"
  13.  
  14. void main(argc, argv)
  15. char     **argv;
  16. int     argc;
  17. {
  18. int dependancies(), make(), err();
  19.  
  20.     if( !(Makefile = fopen(MAKEFILE, "r")) )
  21.         err("can't open %s\n", MAKEFILE);
  22.         
  23.     if( !dependancies() )
  24.         err("Nothing to make");
  25.     else
  26.         make( argc > 1 ? argv[1] : First);
  27.     
  28. } /* main end */
  29.  
  30.  
  31. char    *gmem( numbytes )
  32. int     numbytes;
  33. {
  34.     /* Get numbytes from malloc. Print an error messages and 
  35.        abort if malloc fails, otherwise return a pointer to
  36.        the memory.
  37.     */
  38.     
  39.     char     *calloc();
  40.     char     *p;
  41.     int    err();
  42.     
  43.     if(  !( p = calloc(1, numbytes) ))
  44.         err("Out of memory");
  45.     return p;
  46. } /* gmem end */
  47.  
  48. char     **stov(str, maxvect)
  49. char    *str;
  50. int     maxvect;
  51. {
  52.     /* "Str" is a string of words seperated from each other by
  53.        white space. Stov returns an argv-like array of pointers 
  54.        to chracter pointers, one to each word in the original
  55.        string. The white-space in the original string is replaced
  56.        with nulls. The array of pointers is null-terminated
  57.        array. The program is aborted of it can't get memory.
  58.     */
  59.     
  60.     char **vect, **vp;
  61.     char *gmem();
  62.  
  63.     vp = vect = (char **) gmem( (maxvect + 1) * sizeof(str) );
  64.     while( *str && --maxvect >= 0 )
  65.     {
  66.         skipwhite(str);
  67.         *vp++ = str;
  68.         skipnonwhite(str);
  69.         if(*str)
  70.             *str++ = 0;
  71.     }
  72.     *vp = 0;
  73.     return(vect);
  74. } /* stov end */
  75.  
  76. long    gtime( file )
  77. char     *file;
  78. {
  79.     /* Return the time and date for file.
  80.        
  81.       The DOS time and date are concatenated to form one
  82.       large number. Note that the high bit of this number
  83.       will be set to 1 for all dates after 2043, which will
  84.       cause the date comparisons done in make() to not work.
  85.       THIS ROUTINE IS NOT PORTABLE (because it assumes a 32 bit
  86.       long).
  87.       
  88.     */
  89.  
  90.     long time;
  91.     int fd;
  92.     int open(), err(), close();
  93.  
  94. #ifdef    MICRO_C
  95.     struct stat buf;
  96.     int fstat();
  97.     int result;
  98. #endif
  99.  
  100. #ifdef    LATTICE_C
  101.     long getft();
  102. #endif
  103.  
  104.     if ( (fd = open (file, O_RDONLY)) == -1 )
  105.         return DEFTIME;
  106.  
  107. #ifdef    MICRO_C
  108.     if ( (result = fstat (fd, &buf)) == -1 )
  109.         err("DOS returned error from date/time request");
  110.     time = buf.st_atime;
  111. #endif
  112.  
  113. #ifdef    LATTICE_C
  114.     /* LATTICE uses a different time structure from one returned by */
  115.     /* gmtime() so that it doesn't show the same file time as one you get */
  116.     /* by "dir" command. However, it still can tell the difference */
  117.     /* between new and old files. */
  118.  
  119.  
  120.     if ( (time = getft (fd)) == -1 )
  121.         err("DOS returned error from date/time request");
  122. #endif
  123.  
  124.     if ( close (fd) )
  125.         err("DOS returned error from file close request");
  126.  
  127.     return time;
  128. } /* gtime end */
  129.  
  130. TNODE    *makenode()
  131. {
  132.     /* Create a TNODE, filling it from the makefile
  133.        and return a pointer to it. Return NULL if there are no more
  134.        objects in the makefile.
  135.     */
  136.     
  137.     char     *line, *lp;
  138.     TNODE    *nodep;
  139.     char *getline(), **stov(), **getblock(), *gmem();
  140.     int    err();
  141.     long    gtime();
  142.  
  143.     /* First, skip past any blank lines or comment lines.
  144.        Return  NULL if we reach the end of file
  145.     */
  146.     
  147.     do{
  148.         if( (line = getline(MAXLINE, Makefile)) == NULL )
  149.             return( NULL );
  150.     } while ( *line == 0 || *line == COMMENT );
  151.     
  152.     /* At this point we've gotten what should be the dependancy
  153.        line. Position lp to point at the colon.
  154.     */
  155.  
  156.     for( lp  = line; *lp && *lp != ':'; lp++)
  157.         ;
  158.         
  159.     /* If we find the colon position, lp to point at the first
  160.        non-white character following the colon.
  161.     */
  162.     
  163.     if( *lp != ':' )
  164.         err("missing ':'");    /* This will abort the program */
  165.     else
  166.         for( *lp++ = 0; iswhite(*lp) ; lp++)
  167.         ;
  168.     
  169.     /* Allocate and initialize the TNODE */
  170.     
  171.     nodep            = (TNODE *) gmem( sizeof(TNODE) );
  172.     nodep->being_made    = line;
  173.     nodep->time        = gtime( line );
  174.     nodep->depends_on    = stov( lp, MAXDEP );
  175.     nodep->do_this        = getblock( Makefile );
  176.     
  177.     return( nodep );
  178. } /* makenode end */
  179.  
  180. int dependancies()
  181. {
  182.     /* Manufacture the binary tree of objects to make. First
  183.        is a pointer to the first target file listed in the 
  184.        makefile (i.e. the one to make if one isn't explicitly
  185.        given on the command line). Root is the tree's root pointer.
  186.     */
  187.     
  188.     TNODE    *node, *makenode();
  189.     int     err(), tree();
  190.  
  191.     if( node = makenode() )
  192.     {
  193.         First = node->being_made;
  194.         
  195.         if( !tree(node, &Root) )
  196.             err("Can't insert first node into tree !!!\n");
  197.         
  198.         while( node = makenode() )
  199.             if( !tree(node, &Root) )
  200.                 free(node);
  201.             return 1;
  202.     }
  203.     return 0;
  204. } /* dependancies end */
  205.  
  206.  
  207. char     *getline( maxline, fp)
  208. int maxline;
  209. FILE *fp;
  210. {
  211.     /* Get a line from the stream pointed to by fp.
  212.        "Maxline" is the maximum input line size ( including the
  213.        terminating null. A \ at the end of line is
  214.        recognized as a line continuation, ( the lines
  215.        are concatenated). Buffer space is gotten from malloc.
  216.        If a line is longer than maxline it is truncated (i.e.
  217.        all characters from the maxlineth until a \n or EOF is
  218.        encountered are discarded.
  219.        
  220.       Return: NULL on a malloc failure or the end of file.
  221.             A pointer to the malloced buffer on success.
  222.     */
  223.     
  224.     static char    *buf;
  225.     register char     *bp;
  226.     register int     c, lastc;
  227.     char         *malloc(), *strcpy();
  228.  
  229.  
  230.     /* Two buffers are used, Here, we are getting a worst-case buffer
  231.        that will hold the longest possible line. Later on we'll copy
  232.        the string into a buffer that's the correct size.
  233.     */
  234.     
  235.     if( !(bp = buf = malloc(maxline)) )
  236.         return  NULL;
  237.     while(1)
  238.     {
  239.         /* Get the line from fp. Terminate after maxline
  240.            characters and ignore \n following a \.
  241.         */
  242.         
  243.         Inputline++;         /* Update input line number */
  244.         for( lastc=0; (c = fgetc(fp)) != EOF && c!='\n'; lastc = c)
  245.             if( --maxline > 0 )
  246.                 *bp++ = c;
  247.         if( !(c == '\n' && lastc == '\\') )
  248.             break;
  249.         else if(maxline > 0)    /* erase the \ */
  250.             --bp;
  251.     }
  252.     *bp = 0;
  253.         
  254.     if( (c == EOF && bp == buf) || !(bp = malloc((bp-buf) + 1)) )
  255.     {
  256.         /* If EOF was the first character on the line or
  257.            malloc fails when we try to get a buffer, quit.
  258.         */
  259.             
  260.         free(buf);
  261.         return( NULL );
  262.             
  263.     }
  264.         
  265.     strcpy (bp, buf);    /* Copy the worst-case buffer to the one */
  266.                 /* that is the correct size and ... */
  267.     free ( buf );        /* free the original, worst-case buffer, */
  268.     return ( bp );        /*  returning a pointer to the copy */
  269. } /* getline end */
  270.     
  271.  
  272. char     **getblock( fp )
  273. FILE *fp;
  274. {
  275.     /* Get a block from standard input. A block is a sequences of
  276.        lines terminates by a blank line. The block is returned as
  277.        an array of pointers to strings. At most MAXBLOCK lines can
  278.        be in a block. Leading white space is stripped.
  279.     */
  280.     
  281.     char    *p, *lines[MAXBLOCK], **blockv = lines, *gmem();
  282.     int     blockc  = 0;
  283.     char     *memcpy(), *getline(), *gmem();
  284.     int     err();
  285.  
  286.     do {
  287.         if( !( p = getline(MAXLINE, Makefile) ))
  288.             break;
  289.             
  290.         skipwhite(p);
  291.         
  292.         if( ++blockc <= MAXBLOCK )
  293.             *blockv++ = p;
  294.         else
  295.             err("action too long (max = %d lines)", MAXBLOCK);
  296.     } while(*p);
  297.     
  298.     /* Copy the blockv array into a safe place. Since the array
  299.        returned by getblock is NULL terminated, we need to 
  300.        increment block first.
  301.     */
  302.     
  303.     blockv = (char **) gmem( (blockc + 1) * sizeof(blockv[0]) );
  304.     memcpy( blockv,lines, blockc * sizeof(blockv[0]) );
  305.     blockv[blockc] = NULL;
  306.     
  307.     return blockv;
  308. } /* getblock end */
  309.  
  310.  
  311. int err( msg, param)
  312. char *msg;
  313. int param;
  314. {
  315.     /* Print the error message and exit the program. */
  316.     
  317.     fprintf(stderr, "Mk (%s line %d): ", MAKEFILE, Inputline);
  318.     fprintf(stderr, msg, param);
  319.     exit(1);
  320.     
  321. } /* err end */
  322.  
  323. int serr( msg, param )
  324. char *msg, *param;
  325. {
  326.     /* same as err() except the parameter is a string pointer
  327.        instead pf an int.
  328.     */
  329.     
  330.     fprintf(stderr, "Mk (%s line %d): ", MAKEFILE, Inputline);
  331.     fprintf(stderr, msg, param);
  332.     exit(1);
  333. } /* serr end */
  334.  
  335. int make(what)
  336. char *what;
  337. {    
  338.     /* Actually do the make. the dependancy tree is desc